#ifndef _SRC_BASE_TIME_STAMP_H_
#define _SRC_BASE_TIME_STAMP_H_

#include <string>

#include "src/base/utils.h"

namespace fio66 {
class Timestamp {
 public:
  ///
  /// Constucts an invalid Timestamp.
  ///
  Timestamp() : micro_second_since_epoch_(0) {}
  ~Timestamp() {}
  ///
  /// Constucts a Timestamp at specific time
  ///
  /// @param microSecondsSinceEpoch
  explicit Timestamp(int64_t microSecondsSinceEpochArg)
      : micro_second_since_epoch_(microSecondsSinceEpochArg) {}

  void Swap(Timestamp& that) {
    std::swap(micro_second_since_epoch_, that.micro_second_since_epoch_);
  }

  // default copy/assignment/dtor are Okay

  std::string ToString() const;
  std::string ToFormattedString(bool showMicroseconds = true) const;

  bool Valid() const { return micro_second_since_epoch_ > 0; }

  // for internal usage.
  int64_t MicroSecondsSinceEpoch() const { return micro_second_since_epoch_; }
  time_t SecondsSinceEpoch() const {
    return static_cast<time_t>(micro_second_since_epoch_ /
                               kMicroSecondsPerSecond);
  }

  ///
  /// Get time of now.
  ///
  static Timestamp Now();
  static Timestamp Invalid() { return Timestamp(); }

  static Timestamp FromUnixTime(time_t t) { return FromUnixTime(t, 0); }

  static Timestamp FromUnixTime(time_t t, int microseconds) {
    return Timestamp(static_cast<int64_t>(t) * kMicroSecondsPerSecond +
                     microseconds);
  }

  static constexpr int kMicroSecondsPerSecond = 1000 * 1000;

 private:
  int64_t micro_second_since_epoch_;
};

inline auto operator<=>(Timestamp lhs, Timestamp rhs) {
  return lhs.MicroSecondsSinceEpoch() <=> rhs.MicroSecondsSinceEpoch();
}

inline bool operator==(Timestamp lhs, Timestamp rhs) {
  return lhs.MicroSecondsSinceEpoch() == rhs.MicroSecondsSinceEpoch();
}

// inline bool operator<(Timestamp lhs, Timestamp rhs) {
//   return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch();
// }

///
/// Gets time difference of two timestamps, result in seconds.
///
/// @param high, low
/// @return (high-low) in seconds
/// @c double has 52-bit precision, enough for one-microsecond
/// resolution for next 100 years.
inline double TimeDifference(Timestamp high, Timestamp low) {
  int64_t diff = high.MicroSecondsSinceEpoch() - low.MicroSecondsSinceEpoch();
  return static_cast<double>(diff) / Timestamp::kMicroSecondsPerSecond;
}

///
/// Add @c seconds to given timestamp.
///
/// @return timestamp+seconds as Timestamp
///
inline Timestamp AddTime(Timestamp timestamp, double seconds) {
  int64_t delta =
      static_cast<int64_t>(seconds * Timestamp::kMicroSecondsPerSecond);
  return Timestamp(timestamp.MicroSecondsSinceEpoch() + delta);
}
}  // namespace fio66

#endif  // _SRC_BASE_TIME_STAMP_H_
